package main

// 导入必要的包
import (
	"crypto/tls"    // 提供TLS/SSL加密通信支持
	"encoding/json" // JSON编解码
	"fmt"           // 格式化输入输出
	"io/ioutil"     // IO工具函数
	"log"           // 日志记录
	"net/http"      // HTTP客户端和服务器实现
	"strings"       // 字符串操作
	"time"          // 时间相关功能

	MQTT "github.com/eclipse/paho.mqtt.golang" // MQTT客户端库
)

// getAccessToken 通过OAuth2.0客户端凭证方式获取访问令牌
// 返回值:
//   - string: 访问令牌
//   - error: 错误信息
func getAccessToken() (string, error) {
	// 构建OAuth2.0请求参数
	data := "client_id=5kwl2q94VGG2XHCg&client_secret=6PrvoQIeUUzyThBrUJ9eIprshq7NptXzmu5WyOVc3sqUzjOj84sj9aDwovsmtS6z&grant_type=client_credentials&scope=camera:write room:write alert:write person:write user:write group:write invitation:write person_info:write"
	// 创建POST请求
	req, err := http.NewRequest("POST", "https://oauth.ailecare.cn/v1.0/token", strings.NewReader(data))
	if err != nil {
		return "", err
	}
	// 设置请求头
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	// 发送HTTP请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	// 解析响应数据
	body, _ := ioutil.ReadAll(resp.Body)
	var result map[string]interface{}
	json.Unmarshal(body, &result)

	return result["access_token"].(string), nil
}

// getHeaders 生成包含认证信息的HTTP请求头
// 参数:
//   - token: 访问令牌
//
// 返回值:
//   - map[string]string: 包含Authorization头的map
func getHeaders(token string) map[string]string {
	return map[string]string{
		"Authorization": "Bearer " + token,
	}
}

// getMqttInfo 获取MQTT连接所需的账号信息
// 参数:
//   - headers: HTTP请求头
//
// 返回值:
//   - map[string]string: 包含MQTT用户名和密码的map
//   - error: 错误信息
func getMqttInfo(headers map[string]string) (map[string]string, error) {
	// 创建获取MQTT账号信息的请求
	req, err := http.NewRequest("GET", "https://api.ailecare.cn/v1.0/mqttAccount", nil)
	if err != nil {
		return nil, err
	}

	// 添加请求头
	for key, value := range headers {
		req.Header.Add(key, value)
	}

	// 发送请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// 解析响应数据
	body, _ := ioutil.ReadAll(resp.Body)
	var result map[string]interface{}
	json.Unmarshal(body, &result)

	// 提取MQTT账号信息
	mqttAccount := result["data"].(map[string]interface{})["mqtt_account"].(map[string]interface{})
	return map[string]string{
		"username": mqttAccount["username"].(string),
		"password": mqttAccount["passcode"].(string),
	}, nil
}

// getStreamToken 获取摄像头流媒体token
// 参数:
//   - headers: HTTP请求头
//
// 返回值:
//   - string: 流媒体token
//   - error: 错误信息
func getStreamToken(headers map[string]string) (string, error) {
	// 创建获取stream token的请求
	req, err := http.NewRequest("GET", "https://api.ailecare.cn/v1.0/cameras/23789/streamtoken", nil)
	if err != nil {
		return "", err
	}

	// 添加请求头
	for key, value := range headers {
		req.Header.Add(key, value)
	}

	// 发送请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	// 解析响应数据
	body, _ := ioutil.ReadAll(resp.Body)
	var result map[string]interface{}
	json.Unmarshal(body, &result)

	return result["data"].(map[string]interface{})["stream_token"].(string), nil
}

// MQTT连接成功后的回调函数
// 在连接成功后自动订阅指定主题
var onConnect MQTT.OnConnectHandler = func(client MQTT.Client) {
	fmt.Println("Connected to MQTT broker")
	// 订阅特定摄像头的骨骼点数据主题
	topic := "mobileClient/4012/camera/23992AE621E4AEEE/skeleton/1046099268"
	client.Subscribe(topic, 0, nil)
	fmt.Printf("Subscribed to topic: %s\n", topic)
}

// MQTT消息处理回调函数
// 当收到订阅主题的消息时触发
var onMessage MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
	fmt.Printf("Message received from topic %s: %s\n", msg.Topic(), msg.Payload())
}

func main() {
	// 获取访问token
	token, err := getAccessToken()
	if err != nil {
		log.Fatalf("Error getting access token: %v", err)
	}
	headers := getHeaders(token)

	// 获取MQTT连接信息
	mqttInfo, err := getMqttInfo(headers)
	if err != nil {
		log.Fatalf("Error getting MQTT info: %v", err)
	}

	// 配置MQTT客户端选项
	opts := MQTT.NewClientOptions()
	// 设置MQTT Broker的WebSocket地址
	opts.AddBroker("wss://beijing.altumview.com.cn:8084/mqtt")
	// 设置MQTT连接的用户名和密码
	opts.SetUsername(mqttInfo["username"])
	opts.SetPassword(mqttInfo["password"])
	// 配置TLS（跳过证书验证，仅用于测试环境）
	opts.SetTLSConfig(&tls.Config{
		InsecureSkipVerify: true,
	})
	// 设置连接和消息处理的回调函数
	opts.SetOnConnectHandler(onConnect)
	opts.SetDefaultPublishHandler(onMessage)

	// 创建并连接MQTT客户端
	client := MQTT.NewClient(opts)
	if token := client.Connect(); token.Wait() && token.Error() != nil {
		log.Fatalf("Error connecting to MQTT broker: %v", token.Error())
	}

	// 启动定时器，每9分钟进行一次重新认证
	ticker := time.NewTicker(9 * time.Minute)
	go func() {
		for range ticker.C {
			fmt.Println("Reauthenticating...")
			// 获取新的MQTT连接信息
			mqttInfo, err := getMqttInfo(headers)
			if err != nil {
				log.Fatalf("Error reauthenticating: %v", err)
			}
			// 断开当前连接
			client.Disconnect(250)
			// 更新认证信息
			opts.SetUsername(mqttInfo["username"])
			opts.SetPassword(mqttInfo["password"])
			// 重新连接
			client.Connect()
		}
	}()

	// 保持主程序运行
	select {}
}
